/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../macro/head.h"
#include "../xos/head.h"
#include "../misc/head.h"
#include "file_impl.h"
#include "dir_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static dir_impl::ITEM_DATA xos_item_data;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    dir_impl::dir_impl()
    {}

    dir_impl::~dir_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int dir_impl::get_xos_item_data( ITEM_DATA*& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    int dir_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int dir_impl::term()
    {
        int nRet = 0;
        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////
    // 
    // get full file name path
    // 

    int dir_impl::get_file_path( char * lpszPath, int nLen, const char * lpszFile )
    {
        int nRet = 0;

        const char * p = 0;
        int len = 0;

        if( 0 == nRet )
        {
            if( !lpszPath || ( 0 == strlen( lpszPath ) ) || !lpszFile || ( 0 == strlen( lpszFile ) ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            p = strrchr( lpszFile, '/' );

            if( !p )
            {
                nRet = 1;
            }
            else
            {
                len = p - lpszFile;
            }
        }

        if( 0 == nRet )
        {
            if( nLen <= len )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            strncpy( lpszPath, lpszFile, len );
        }

        return nRet;
    }

    // 
    // create dir and sub dirs
    // 
    int dir_impl::create_directory( const char * lpszPath )
    {
        using namespace std;

        int nRet = 0;

        nRet = mkdir( lpszPath, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );

        if( -1 == nRet )
        {
            if( 17 != errno )
            {
            }
            else
            {
                nRet = 0;
            }
        }
        else
        {
            nRet = 0;
        }

        return nRet;
    }

    // 
    // delete dir and sub dirs
    // 
    int dir_impl::delete_directory( const char * lpszPath )
    {
        int nRet = 0;

        i_misc* pMisc = mgr::get()->misc();
        char file[4096] = { 0 };
        struct stat st = { 0 };
        struct dirent * ent = 0;
        DIR * pDir = 0;

        pDir = opendir( lpszPath );

        while( pDir && ( ent = readdir( pDir ) ) )
        {
            strcpy( file, lpszPath );
            pMisc->path_append( file, sizeof( file ), ent->d_name);
            lstat( file, &st );

            if( S_ISDIR( st.st_mode ) )
            {
                if( ( 0 != strcmp( ent->d_name, "." ) ) && ( 0 != strcmp( ent->d_name, ".." ) ) )
                {
                    delete_directory( file );
                }
            }
            else
            {
                delete_file( file );
            }
        }

        if( pDir )
        {
            closedir( pDir );
            pDir = 0;
        }

        remove( lpszPath );

        return nRet;
    }

    // 
    // if a dir exists
    // 
    int dir_impl::is_dir_exist( const char * lpszPath )
    {
        int ret = 0;

        struct stat buf = { 0 };

        if( 0 == ret )
        {
            int r = stat( lpszPath, &buf );
            if( -1 == r )
            {
                ret = 1;
            }
        }

        // S_ISDIR来判断是否为目录
        // if is file - S_ISREG
        if( ( 0 == ret ) && !S_ISDIR( buf.st_mode ) )
        {
            ret = 1;
        }

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////// 

    // 
    // scan all dirs and files into property:
    // 
    //   dirs : *xos_box::i_str_property
    //   file : *i_file
    // 
    // nDepth : 
    //    -1  : no limit
    //     0  : no scan
    //  other : depth
    // 
    // if lpszPath do not exitst, *ppv is null
    // 
    int dir_impl::scan_dir_and_files( enumFileType eType, const char * lpszExtFilter, const char* lpszPath, xos_box::i_str_property** ppv, int nDepth )
    {
        int ret = 0;

        xos_common::i_misc * pComMisc = mgr::container()->common()->misc();
        xos_box::i_string * pString = mgr::container()->box()->string();
        xos::i_crt * pCrt = mgr::container()->xos()->crt();

        xos_box::i_str_property* pProperty = 0;
        bool bFile = eType & FILE_TYPE_FILE;
        bool bDir = eType & FILE_TYPE_DIR;

        struct dirent* ent = 0;
        DIR* pDir = 0;

        struct stat st = { 0 };

        {
            pProperty = mgr::container()->box()->get_str_prop();
            *ppv = pProperty;
        }

        if( 0 != nDepth )
        {
            pDir = opendir( lpszPath );
            nDepth--;
        }

        while( pDir && (ent = readdir( pDir )) )
        {
            {
                pString->set( lpszPath );
                mgr::get()->misc()->path_append( pString, ent->d_name );
                lstat( pString->get(0, 0), &st);
            }

            if( S_ISDIR( st.st_mode ) )
            {
                if( (0 != strcmp( ent->d_name, "." )) && (0 != strcmp( ent->d_name, ".." )) && bDir )
                {
                    pString->set( lpszPath );
                    mgr::get()->misc()->path_append( pString, ent->d_name );
                    xos_box::i_str_property* pProp = 0;
                    scan_dir_and_files( eType, lpszExtFilter, pString->get( 0, 0 ), &pProp, nDepth );
                    pProperty->set_str_prop( ent->d_name, pProp, true );
                    pProp = 0;
                }
            }
            else if( bFile )
            {
                bool bSelectThisFile = true;
                if( lpszExtFilter )
                {
                    bSelectThisFile = false;
                    const char * lpszExt = pComMisc->ext( ent->d_name, 0 );
                    if( lpszExt && ( 0 == pCrt->strcmp( lpszExt, lpszExtFilter ) ) )
                    {
                        bSelectThisFile = true;
                    }
                }
                if( bSelectThisFile )
                {
                    file_impl::T * p = 0;
                    xos_stl::init_pool_item( p );
                    p->m_file_name = ent->d_name;
                    p->m_cTime = st.st_ctime;
                    p->m_aTime = st.st_atime;
                    p->m_mTime = st.st_mtime;
                    pProperty->set_obj( ent->d_name, p, true );
                    p = 0;
                }
            }
        }

        if( pDir )
        {
            closedir( pDir );
            pDir = 0;
        }

        xos_stl::release_interface( pString );

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////

    // 
    // get file size and time
    // 
    int dir_impl::get_file_size_and_time( const char * lpszFile, int64_t * lpSize64, int64_t * lpCreateTime, int64_t * lpAccessTime, int64_t * lpModifyTime )
    {
        int nRet = 0;

        struct stat st = { 0 };

        if( 0 == nRet )
        {
            nRet = stat( lpszFile, &st );
        }

        if( ( 0 == nRet ) && lpCreateTime )
        {
            *lpCreateTime = st.st_ctime;
        }

        if( ( 0 == nRet ) && lpAccessTime )
        {
            *lpAccessTime = st.st_atime;
        }

        if( ( 0 == nRet ) && lpModifyTime )
        {
            *lpModifyTime = st.st_mtime;
        }

        if( ( 0 == nRet ) && lpSize64 )
        {
            *lpSize64 = st.st_size;
        }

        return nRet;
    }

    // 
    // 设置文件时间。linux32下create time无效
    // 
    int dir_impl::set_file_time( const char * lpszFile, int64_t cTime, int64_t aTime, int64_t mTime )
    {
        int ret = 0;

        struct utimbuf tm = { 0 };

        tm.actime = ( time_t )aTime;
        tm.modtime = ( time_t )mTime;

        ret = utime( lpszFile, &tm );

        return ret;
    }

    // 
    // if a file exists
    // 
    int dir_impl::is_file_exist( const char * lpszFileName )
    {
        int ret = 0;

        struct stat buf = { 0 };

        if( 0 == ret )
        {
            int r = stat( lpszFileName, &buf );
            if( -1 == r )
            {
                ret = 1;
            }
        }

        // if is file - S_ISREG
        // S_ISDIR来判断是否为目录
        if( ( 0 == ret ) && !S_ISREG( buf.st_mode ) )
        {
            ret = 1;
        }

        return ret;
    }

    // 
    // delete a file
    // 
    int dir_impl::delete_file( const char * lpszFileName )
    {
        int nRet = 0;
        nRet = remove( lpszFileName );
        return nRet;
    }

    // 
    // rename a file
    // 
    int dir_impl::rename_file( const char * lpszDesName, const char * lpszSrcName )
    {
        int nRet = 0;
        nRet = rename( lpszSrcName, lpszDesName );
        return nRet;
    }
} // xos
